home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Taifun / Taifun 056 (1988-05-15)(Ossowski, Stefan)(DE)(PD).zip / Taifun 056 (1988-05-15)(Ossowski, Stefan)(DE)(PD).adf / Mackie / Mackie.c < prev    next >
C/C++ Source or Header  |  1988-04-13  |  21KB  |  679 lines

  1. /*
  2.     Modified to work with Manx 3.4b; probably won't work with Lattice.
  3.                                 Based on:
  4.                                                                              */
  5. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  6. /* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
  7. /* |. o.| || This program may not be distributed without the permission of   */
  8. /* | .  | || the authors.                                                    */
  9. /* | o  | ||    Dave Baker     Ed Burnette  Stan Chow    Jay Denebeim        */
  10. /* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
  11. /* ======          BBS:(919)-471-6436      VOICE:(919)-469-4210              */ 
  12. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  13. /*
  14.  * VERY loosely based on the input.device example by Rob Peck, 12/1/85
  15.  */
  16. /* * * * * * * * * INCLUDE FILES * * * * * * * * * * * */
  17. #include <exec/types.h>
  18. #include <exec/nodes.h>
  19. #include <exec/lists.h>
  20. #include <exec/memory.h>
  21. #include <exec/interrupts.h>
  22. #include <exec/ports.h>
  23. #include <exec/libraries.h>
  24. #include <exec/io.h>
  25. #include <exec/tasks.h>
  26. #include <exec/execbase.h>
  27. #include <exec/devices.h>
  28. #include <devices/timer.h>
  29. #include <devices/input.h>
  30. #include <devices/inputevent.h>
  31. #include <intuition/intuition.h>
  32. #include <libraries/dos.h>
  33. #include <graphics/gfxmacros.h>
  34. #include <hardware/custom.h>
  35. #include <hardware/dmabits.h>
  36. #include "functions.h"
  37.  
  38. /* * * * * * * * * * * CONSTANTS * * * * * * * * * * * * */
  39. #define PORTNAME     "Mackie.port"
  40. #define TIMEINTERVAL 1L      /* in seconds */
  41. #define DEFTIME      300     /* two minute timeout */
  42. #define MAXCMD       200
  43. #define DEFKEY    0x45
  44. #define DEFCMD    "NEWCLI >NIL: <NIL:"
  45. #define KILLMSG "\x9B1mMackie\x9B0m Terminating\n"
  46. #define PARAMMSG "\x9B1mError in parameter!\x9B0m\n"
  47. #define BANNER "\x9B0;33mMackie\x9B0m by Tomas Rokicki - Copyright \xa9 1987 Radical Eye Software\n"
  48. #define USAGE "\x9B0;33mUsage: Mackie [-q] [-l] [-b] [time] [\"command\"]\x9B0m\n"
  49. /* * * * * * * * * * * GLOBAL VARIABLES * * * * * * * * * */
  50. typedef struct
  51.    {
  52.    struct Task          *buddy ;
  53.    ULONG                 creatclisig ;
  54.    ULONG                 unblanksig ;
  55.    ULONG                 frontsig ;
  56.    ULONG                 noevents ;
  57.    short                 creatsignum ;
  58.    short                 blanksignum ;
  59.    short                 replysignum ;
  60.    short                 frontsignum ;
  61.    short                 key ;
  62.    short                 frontkey ;
  63.    short                 draw ;
  64.    struct Screen        *blankscreen ;
  65.    } GLOBAL_DATA;
  66. struct Task *task ;
  67. long taskreply ; /* the signal the line drawing task will return */
  68. #define STACKSIZE (1000)
  69. long stackmem[STACKSIZE/4] ;
  70. struct MsgPort *FindPort(), *CreatePort();
  71. void DeletePort();
  72.  
  73. struct OURMSG {
  74.  struct Message msgpart;
  75.  short key;
  76.  short interval;
  77.  short draw ;
  78.  char cmd[MAXCMD];
  79.  };
  80.  
  81. struct FileHandle *_Backstdout;  /* standard output when run in background */
  82.  
  83. /************************************************************************/
  84. /* the handler subroutine - called through the handler stub             */
  85. /************************************************************************/
  86. extern void HandlerInterface();
  87. void foobar() {
  88. #asm
  89. _HandlerInterface:
  90.     movem.l a4,-(a7)
  91.     movem.L    A0/A1,-(A7)
  92.     jsr    _geta4#
  93.     jsr    _myhandler
  94.     addq.L    #8,A7
  95.     movem.L    (a7)+,a4
  96.     rts
  97. #endasm
  98. }
  99. struct InputEvent *myhandler(ev, gptr)
  100. struct InputEvent *ev;      /* and a pointer to a list of events */
  101. register GLOBAL_DATA *gptr;      /* Everything we need to know about */
  102. {
  103.    register struct InputEvent *ep, *laste;
  104.    int key ;
  105.    /* run down the list of events to see if they pressed the magic button */
  106.    for (ep = ev, laste = NULL; ep != NULL; ep = ep->ie_NextEvent) {
  107.       if ((ep->ie_Class == IECLASS_RAWKEY)    &&
  108.              (ep->ie_Qualifier & IEQUALIFIER_LCOMMAND) &&
  109.              ((ep->ie_Code == gptr->key) ||
  110.               ((ep->ie_Qualifier & IEQUALIFIER_LSHIFT) &&
  111.                (ep->ie_Code & 128) == 0))) {
  112.          if (ep->ie_Qualifier & IEQUALIFIER_LSHIFT)
  113.             gptr->frontkey = key = ep->ie_Code ;
  114.          else
  115.             key = -1 ;
  116.          /* we can handle this event so take it off the chain */
  117.          if (laste == NULL)
  118.             ev = ep->ie_NextEvent;
  119.          else
  120.             laste->ie_NextEvent = ep->ie_NextEvent;
  121.          /* now tell him to create the new cli */
  122.          if (key == -1)
  123.             Signal(gptr->buddy, gptr->creatclisig);
  124.          else
  125.             Signal(gptr->buddy, gptr->frontsig);
  126.       } else
  127.          laste = ep;
  128.       if (ep->ie_Class != IECLASS_TIMER) {
  129.          gptr->noevents = 0;
  130.          if (gptr->blankscreen != NULL)
  131.             Signal(gptr->buddy, gptr->unblanksig);
  132.       }
  133.    }
  134.    /* pass on the pointer to the event */
  135.    return(ev);
  136. }
  137.  
  138. /* * * * * * * * * * * EXTERNAL ROUTINES * * * * * * * * * */
  139. struct IntuitionBase *IntuitionBase;
  140. struct GfxBase       *GfxBase;
  141. struct DosLibrary    *DosBase;
  142. struct NewScreen      NewScreen = 
  143.    { 0, 0, 320, 30, 1, 0, 1, NULL, CUSTOMSCREEN, NULL, NULL, NULL, NULL };
  144.  
  145. extern struct MsgPort  *CreatePort();
  146. struct IOStdReq *CreateIOReq();
  147. void DeleteIOReq();
  148.  
  149. /************************************************************************/
  150. /* Queue a timer to go off in a given number of seconds                 */
  151. /************************************************************************/
  152. void QueueTimer(tr,seconds)
  153. struct timerequest *tr;
  154. ULONG seconds;
  155. {
  156.    tr->tr_node.io_Command = TR_ADDREQUEST;   /* add a new timer request */
  157.    tr->tr_time.tv_secs =  seconds;            /* seconds */
  158.    tr->tr_time.tv_micro = 0;
  159.    SendIO( (struct IORequest *)tr );
  160. }
  161.  
  162. /************************************************************************/
  163. /* the main program to do the popcli stuff                              */
  164. /************************************************************************/
  165. GLOBAL_DATA global;
  166. main(argc, argv)
  167. int argc ;
  168. char *argv[] ;
  169. {
  170.    struct MsgPort *port;
  171.    int stay = 0;
  172.    struct OURMSG *msg;
  173.  
  174.    char cmdstr[MAXCMD];
  175.    short key, timeout;
  176.    struct FileHandle *nullfh = NULL ;
  177.    ULONG sig, timersig;
  178.    struct timerequest *timerreq;
  179.    struct MsgPort     *timerport;
  180.    struct MsgPort     *inputDevPort;
  181.    struct IOStdReq    *inputRequestBlock;
  182.    struct Interrupt      handlerStuff;
  183.    char *cmd ;
  184.    int draw = 0 ;
  185.  
  186.    _Backstdout = Output() ;
  187.    SetTaskPri(FindTask(0L), 20L) ;
  188.    global.creatsignum  = -1;
  189.    global.blanksignum  = -1;
  190.    global.replysignum  = -1;
  191.    global.frontsignum  = -1;
  192.    global.blankscreen  = NULL;
  193.    global.key          = DEFKEY ;
  194.    global.draw         = 1 ;
  195.    timerreq            = NULL;
  196.    timerport           = NULL;
  197.    inputDevPort        = NULL;
  198.    inputRequestBlock   = NULL;
  199.    /* now see if we are already installed */
  200.    if ((port = FindPort(PORTNAME)) == NULL) {
  201.       stay = 1; /* remember to hang around when we are done */
  202.       /* not installed, we need to install our own port */
  203.       if ((port = CreatePort(PORTNAME,0L)) == NULL)
  204.          goto abort;
  205.    }
  206.    /* now send the parameter to the waiting program */
  207.    if ((msg = (struct OURMSG *)
  208.        AllocMem((long)sizeof(struct OURMSG), MEMF_CLEAR|MEMF_PUBLIC)) == NULL)
  209.       goto abort;
  210.  
  211.    /* fill in the message information */
  212.    msg->msgpart.mn_Length = sizeof(struct OURMSG);
  213.    strcpy(cmdstr, DEFCMD);
  214.    timeout = 0 ;
  215.    key = 0 ;
  216.    msg->cmd[0] = 0;
  217.    /* if we were run from CLI then output our banner and process parameters */
  218.    if (argc > 0) {
  219.       /* display our copyright */
  220.       if (stay && _Backstdout)
  221.          Write(_Backstdout, BANNER, (long)sizeof(BANNER));
  222.       if (argc == 1 && _Backstdout)
  223.          Write(_Backstdout, USAGE, (long)sizeof(USAGE));
  224.       argc-- ;
  225.       argv++ ;
  226.       while (argc > 0) {
  227.          cmd = argv[0] ;
  228.          if (*cmd == '-') {
  229.             cmd++ ;
  230.             switch (*cmd) {
  231. case 'q' : case 'Q' :
  232.                key = -1 ;
  233.                if (_Backstdout)
  234.                   Write(_Backstdout, KILLMSG, (long)sizeof(KILLMSG));
  235.                break ;
  236. case 'l' : case 'L' :
  237.                draw = 1 ;
  238.                break ;
  239. case 'b' : case 'B' :
  240.                draw = -1 ;
  241.                break ;
  242. default :
  243.                if (_Backstdout)
  244.                   Write(_Backstdout, PARAMMSG, (long)sizeof(PARAMMSG));
  245.             }
  246.          } else if ('0' <= *cmd && *cmd <= '9') {
  247.             timeout = 0;
  248.             while ((*cmd >= '0') && (*cmd <= '9'))
  249.                timeout = (timeout*10) + *cmd++ - '0';
  250.             if (timeout <= 0)
  251.                timeout = DEFTIME;
  252.          } else {
  253.             strcpy(msg->cmd, cmd) ;
  254.          }
  255.          argc-- ;
  256.          argv++ ;
  257.       }
  258.    }
  259.    if (draw)
  260.       global.draw = draw ;
  261.    msg->interval = timeout;
  262.    msg->key = key;
  263.    msg->draw = draw ;
  264.    PutMsg(port,(struct Message *)msg);
  265.    if (!stay) goto abort;
  266.    if (timeout == 0)
  267.       timeout = DEFTIME ;
  268.    global.blankscreen = NULL;
  269.    global.buddy = FindTask(0L);
  270.    global.noevents = 0;
  271.    nullfh = Open("NIL:", MODE_NEWFILE);
  272.    if (((inputDevPort = CreatePort(0L,0L)) == NULL) ||
  273.       ((inputRequestBlock =
  274.           CreateIOReq(inputDevPort, (long)sizeof(struct IOStdReq))) == NULL) ||
  275.       ((timerport = CreatePort(0L,0L)) == NULL) ||
  276.       ((timerreq  = (struct timerequest *)
  277.           CreateIOReq(timerport, (long)sizeof(struct timerequest))) == NULL) ||
  278.       ((global.creatsignum = AllocSignal(-1L)) == -1) ||
  279.       ((global.blanksignum = AllocSignal(-1L)) == -1) ||
  280.       ((global.replysignum = AllocSignal(-1L)) == -1) ||
  281.       ((global.frontsignum = AllocSignal(-1L)) == -1) ||
  282.       ((GfxBase = (struct GfxBase *)
  283.                   OpenLibrary("graphics.library", 0L)) == NULL) ||
  284.       ((IntuitionBase = (struct IntuitionBase *)
  285.                         OpenLibrary("intuition.library", 0L)) == NULL) ||
  286.       OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timerreq, 0L) ||
  287.       OpenDevice("input.device",0L,(struct IORequest *)inputRequestBlock,0L))
  288.          goto abort;
  289.    handlerStuff.is_Data = (APTR)&global;
  290.    handlerStuff.is_Code = HandlerInterface;
  291.    handlerStuff.is_Node.ln_Pri = 51;
  292.    timersig            = (1L << timerport->mp_SigBit);
  293.    global.creatclisig  = 1L << global.creatsignum;
  294.    global.unblanksig   = 1L << global.blanksignum;
  295.    global.frontsig     = 1L << global.frontsignum;
  296.    inputRequestBlock->io_Command = IND_ADDHANDLER;
  297.    inputRequestBlock->io_Data    = (APTR)&handlerStuff;
  298.    DoIO((struct IORequest *)inputRequestBlock);
  299.    QueueTimer(timerreq, TIMEINTERVAL);
  300.    for(;;) {         /* FOREVER */
  301.       sig = Wait( global.creatclisig | global.unblanksig | timersig |
  302.                   global.frontsig);
  303.       /* see if they asked us to change the interval */
  304.       if ((msg = (struct OURMSG *)GetMsg(port)) != NULL) {
  305.          if (msg->cmd[0]) strcpy(cmdstr, msg->cmd);
  306.          if (msg->key)
  307.             global.key = msg->key;
  308.          if (msg->interval)
  309.             timeout    = msg->interval;
  310.          if (msg->draw)
  311.             global.draw = msg->draw ;
  312.          FreeMem((char *)msg, (long)msg->msgpart.mn_Length);
  313.          if (msg->key == -1) goto abort;
  314.       }
  315.       if ((sig & global.unblanksig) && global.blankscreen)
  316.          screenunblank() ;
  317.       if (sig & global.creatclisig) {
  318.          WBenchToFront();
  319.          (void)Execute(cmdstr,nullfh,nullfh);
  320.       }
  321.       if ((sig & global.frontsig) && (key = global.frontkey)) {
  322.          global.frontkey = 0 ;
  323.          if ((16 <= key && key <= 25) ||
  324.              (32 <= key && key <= 40) ||
  325.              (49 <= key && key <= 55)) {
  326.             key = "qwertyuiop......asdfghjkl........zxcvbnm"[key-16] ;
  327. /*
  328.  *   Now we have a key, so we have to find a process with that name and
  329.  *   bring her to front.
  330.  */
  331.          }
  332.       }
  333.       if (sig & timersig) {
  334.          /* get rid of the message */
  335.          (void)GetMsg(timerport);
  336.          QueueTimer(timerreq, TIMEINTERVAL);
  337.          if (task)
  338.             SetTaskPri(task, 10L) ;
  339.          if ((global.noevents++ >= timeout) && (global.blankscreen == NULL))
  340.             blankscreen() ;
  341.       }
  342.    }
  343. abort:
  344.    if (timerreq != NULL) {
  345.       if (timerreq->tr_node.io_Device != NULL)
  346.          CloseDevice((struct IORequest *)timerreq);
  347.       DeleteIOReq((struct IOStdReq *)timerreq);
  348.    }
  349.    if (inputRequestBlock != NULL) {
  350.       if (inputRequestBlock->io_Device != NULL) {
  351.          inputRequestBlock->io_Command = IND_REMHANDLER;
  352.          inputRequestBlock->io_Data = (APTR)&handlerStuff;
  353.          DoIO((struct IORequest *)inputRequestBlock);
  354.          CloseDevice((struct IORequest *)inputRequestBlock);
  355.       }
  356.       DeleteIOReq(inputRequestBlock);
  357.    }
  358.    screenunblank() ;
  359.    if (timerport != NULL)          DeletePort(timerport);
  360.    if (global.creatsignum != -1)   FreeSignal(global.creatsignum);
  361.    if (global.blanksignum != -1)   FreeSignal(global.blanksignum);
  362.    if (global.replysignum != -1)   FreeSignal(global.replysignum);
  363.    if (global.frontsignum != -1)   FreeSignal(global.frontsignum);
  364.    if (IntuitionBase != NULL)      CloseLibrary((struct Library *)IntuitionBase);
  365.    if (GfxBase != NULL)            CloseLibrary((struct Library *)GfxBase);
  366.    if (inputDevPort != NULL)       DeletePort(inputDevPort);
  367.    if (stay && (port != NULL))     DeletePort(port);
  368.    if (nullfh)                     Close(nullfh);
  369.    SetTaskPri(FindTask(0L), 0L) ;
  370. }
  371.  
  372. struct IOStdReq *
  373. CreateIOReq(port, size)
  374. struct MsgPort *port;
  375. long size;
  376. {
  377.    struct IOStdReq *ioReq;
  378.  
  379.    if ((ioReq = (struct IOStdReq *)
  380.                 AllocMem(size, MEMF_CLEAR | MEMF_PUBLIC)) != NULL) {
  381.       ioReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  382.       ioReq->io_Message.mn_Node.ln_Pri  = 0;
  383.       ioReq->io_Message.mn_Length       = size;
  384.       ioReq->io_Message.mn_ReplyPort    = port;
  385.    }
  386.    return(ioReq);
  387. }
  388.  
  389. void DeleteIOReq(ioReq)
  390. struct IOStdReq *ioReq;
  391. {
  392.    ioReq->io_Message.mn_Node.ln_Type = 0xff;
  393.    ioReq->io_Device = (struct Device *) -1;
  394.    ioReq->io_Unit = (struct Unit *) -1;
  395.    FreeMem( (char *)ioReq, (long)ioReq->io_Message.mn_Length);
  396. }
  397. /*
  398.  *   All of this stuff down here was written by Tomas Rokicki.
  399.  *   (C) Copyright 1987, Radical Eye Software.
  400.  */
  401. #include "graphics/gfxbase.h"
  402. /*
  403.  *   The maximum number of lines on the screen at once.
  404.  */
  405. #define MAXLINES (100)
  406. /*
  407.  *   The external variables we access.
  408.  */
  409. struct RastPort *rastport ;
  410. short screenheight, screenwidth ;
  411. /*
  412.  *   Some locals to this file.
  413.  */
  414. static struct NewScreen newscreen = {
  415.    0, 0,
  416.    640, 400,
  417.    1,
  418.    0, 1,
  419.    HIRES | LACE | SCREENQUIET,
  420.    CUSTOMSCREEN,
  421.    NULL,
  422.    NULL,
  423.    NULL,
  424.    NULL } ;
  425. /*
  426.  *   This routine opens a screen and fires off the task if apropriate.
  427.  */
  428. void taskrout() ;
  429. blankscreen() {
  430.    screenheight = 2 * GfxBase->NormalDisplayRows ;
  431.    screenwidth = GfxBase->NormalDisplayColumns ;
  432.    newscreen.Height = screenheight ;
  433.    newscreen.Width = screenwidth ;
  434.    if (global.draw == -1 || AvailMem(MEMF_CHIP) < 70000L ||
  435.              (global.blankscreen = OpenScreen(&newscreen)) == NULL) {
  436.       if ((global.blankscreen = OpenScreen(&NewScreen)) != NULL) {
  437.          SetRGB4(&(global.blankscreen->ViewPort), 0L, 0L, 0L, 0L);
  438.          OFF_DISPLAY ;
  439.       }
  440.    } else {
  441.       if (global.blankscreen == NULL &&
  442.           (global.blankscreen = OpenScreen(&newscreen))==NULL)
  443.          return ;
  444. /*
  445.  *   Turning off the sprites is a little bit tricky.  A simple OFF_SPRITE
  446.  *   will continue to display the data in the current sprite registers.
  447.  *   This happens most often with the cursor.  To fix, we simply clear out
  448.  *   the sprite control registers after turning the sprites off.  This
  449.  *   might break all of the sprites when the system comes back up . . .
  450.  */
  451.       OFF_SPRITE ;
  452.       custom.spr[0].ctl = 0 ;
  453.       custom.spr[1].ctl = 0 ;
  454.       custom.spr[2].ctl = 0 ;
  455.       custom.spr[3].ctl = 0 ;
  456.       custom.spr[4].ctl = 0 ;
  457.       custom.spr[5].ctl = 0 ;
  458.       custom.spr[6].ctl = 0 ;
  459.       custom.spr[7].ctl = 0 ;
  460.       SetRGB4(&(global.blankscreen->ViewPort), 0L, 0L, 0L, 0L) ;
  461.       rastport = &(global.blankscreen->RastPort) ;
  462.       SetAPen(rastport, 0L) ;
  463.       Forbid() ;
  464.       RectFill(rastport, 0L, 0L, (long)screenwidth-1, 30L) ;
  465.       Permit() ;
  466.       SetAPen(rastport, 1L) ;
  467.       task = (struct Task *)AllocMem((long)sizeof(struct Task),
  468.                 MEMF_CLEAR | MEMF_PUBLIC) ;
  469.       if (task != NULL) {
  470.          task->tc_Node.ln_Pri = 10 ;
  471.          task->tc_Node.ln_Type = NT_TASK ;
  472.          task->tc_Node.ln_Name = "ri.Lines" ;
  473.          task->tc_SPLower = (APTR)stackmem ;
  474.          task->tc_SPUpper = task->tc_SPReg = (APTR)(stackmem + STACKSIZE/4 - 8) ;
  475.          AddTask(task, taskrout, 0L) ;
  476.       }
  477.    }
  478. }
  479. /*
  480.  *   Unblank the screen.  We kill the task with the standard ^C kill signal.
  481.  */
  482. screenunblank() {
  483.    if (task != NULL) {
  484.       Signal(task, 1L << SIGBREAKB_CTRL_C) ;
  485.       SetTaskPri(task, 11L) ;
  486.       Wait(1L << global.replysignum) ;
  487.       RemTask(task);
  488.       FreeMem(task, (long)sizeof(struct Task)) ;
  489.       task = NULL ;
  490.    }
  491.    if (global.blankscreen != NULL) {
  492.       CloseScreen(global.blankscreen);
  493.       global.blankscreen = NULL ;
  494.       ON_DISPLAY ;
  495.       ON_SPRITE ;
  496.    }
  497. }
  498. /*
  499.  *   This routine returns a random value from 0 to n-1.
  500.  */
  501. int randm(i)
  502. int i ;
  503. {
  504.    static long seed ;
  505.    long rval ;
  506.  
  507.    if (seed == 0)
  508.       seed = 323214521 + global.blankscreen->MouseX +
  509.               global.blankscreen->MouseY ;
  510.    seed = seed * 123213 + 121 ;
  511.    rval = (seed >> 5) & 65535 ;
  512.    return ((i * rval) >> 16) ;
  513. }
  514. /*
  515.  *   This routine sets x and y values to a random number.
  516.  */
  517. static long x, y ;
  518. randomxy() {
  519.    x = randm(screenwidth) ;
  520.    y = randm(screenheight) ;
  521. }
  522. /*
  523.  *   Main routines are always fun.
  524.  */
  525. short x1store[MAXLINES], y1store[MAXLINES] ;
  526. short x2store[MAXLINES], y2store[MAXLINES] ;
  527. short ptr ;
  528. short dx1, dy1, dx2, dy2 ;
  529. short ox1, oy1, ox2, oy2 ;
  530. short nx1, ny1, nx2, ny2 ;
  531. short dr, dg, db ;
  532. short or, og, ob ;
  533. short nr, ng, nb ;
  534. /*
  535.  *   Initialize things for the first lines.
  536.  */
  537. startlines() {
  538.    ptr = 0 ;
  539.    if (dx1 == 0) {
  540.       ox1 = randm(screenwidth) ;
  541.       ox2 = randm(screenwidth) ;
  542.       oy1 = randm(screenheight) ;
  543.       oy2 = randm(screenheight) ;
  544.       dx1 = 3 ;
  545.       dx2 = 4 ;
  546.       dy1 = 1 ;
  547.       dy2 = 6 ;
  548.       nr = 53 ;
  549.       ng = 33 ;
  550.       nb = 35 ;
  551.       dr = -3 ;
  552.       dg = 5 ;
  553.       db = 7 ;
  554.    }
  555.    SetRGB4(&(global.blankscreen->ViewPort), 0L, 0L, 0L, 0L) ;
  556.    SetRGB4(&(global.blankscreen->ViewPort), 1L, (long)(nr >> 3),
  557.                                  (long)(ng >> 3), (long)(nb >> 3)) ;
  558. }
  559. /*
  560.  *   Advance the number by the delta, and check the boundaries.
  561.  */
  562. adv(o, d, n, w)
  563. short *o, *d, *n ;
  564. short w ;
  565. {
  566.    *n = *o + *d ;
  567.    if (*n < 0) {
  568.       *n = 0 ;
  569.       *d = randm(6) + 1 ;
  570.    } else if (*n >= w) {
  571.       *n = w - 1 ;
  572.       *d = - randm(6) - 1 ;
  573.    }
  574. }
  575. /*
  576.  *   Advance the two points which make up the lines.
  577.  */
  578. advancelines() {
  579.    adv(&ox1, &dx1, &nx1, screenwidth) ;
  580.    adv(&ox2, &dx2, &nx2, screenwidth) ;
  581.    adv(&oy1, &dy1, &ny1, screenheight) ;
  582.    adv(&oy2, &dy2, &ny2, screenheight) ;
  583. }
  584. /*
  585.  *   Draw a new set of lines.
  586.  */
  587. drawnew() {
  588.    x1store[ptr] = ox1 = nx1 ;
  589.    x2store[ptr] = ox2 = nx2 ;
  590.    y1store[ptr] = oy1 = ny1 ;
  591.    y2store[ptr] = oy2 = ny2 ;
  592.    Move(rastport, (long)ox1, (long)oy1) ;
  593.    Draw(rastport, (long)ox2, (long)oy2) ;
  594.    Draw(rastport, (long)(screenwidth-ox1-1), (long)(screenheight-oy1-1)) ;
  595.    Draw(rastport, (long)(screenwidth-ox2-1), (long)(screenheight-oy2-1)) ;
  596.    Draw(rastport, (long)ox1, (long)oy1) ;
  597.    ptr++ ;
  598.    if (ptr == MAXLINES)
  599.       ptr = 0 ;
  600. }
  601. /*
  602.  *   Erase the old line.
  603.  */
  604. eraseold() {
  605.    short oldpen ;
  606.  
  607.    oldpen = rastport->FgPen ;
  608.    SetAPen(rastport, 0L) ;
  609.    Move(rastport, (long)x1store[ptr], (long)y1store[ptr]) ;
  610.    Draw(rastport, (long)x2store[ptr], (long)y2store[ptr]) ;
  611.    Draw(rastport, (long)(screenwidth-x1store[ptr]-1),
  612.                   (long)(screenheight-y1store[ptr]-1)) ;
  613.    Draw(rastport, (long)(screenwidth-x2store[ptr]-1), 
  614.                   (long)(screenheight-y2store[ptr]-1)) ;
  615.    Draw(rastport, (long)x1store[ptr], (long)y1store[ptr]) ;
  616.    SetAPen(rastport, (long)oldpen) ;
  617. }
  618. /*
  619.  *   This routine mucks with the colors.
  620.  */
  621. colors() {
  622.    or = nr ;
  623.    og = ng ;
  624.    ob = nb ;
  625.    adv(&or, &dr, &nr, 128) ;
  626.    adv(&og, &dg, &ng, 128) ;
  627.    adv(&ob, &db, &nb, 128) ;
  628.    SetRGB4(&(global.blankscreen->ViewPort), 1L, (long)(nr >> 3),
  629.                                     (long)(ng >> 3), (long)(nb >> 3)) ;
  630. }
  631. /*
  632.  *   Our actual task, in an infinite loop.
  633.  */
  634. void taskrout() {
  635.    long i ;
  636.    struct Task *task ;
  637.  
  638.    geta4() ;
  639.    task = FindTask(0L) ;
  640.    startlines() ;
  641.    for (i=0; i<MAXLINES; i++) {
  642.       advancelines() ;
  643.       drawnew() ;
  644.       if (SetSignal(0L, 0L))
  645.          goto done ;
  646.    }
  647.    colors() ;
  648.    while (SetSignal(0L, 0L)==0) {
  649.       if (task->tc_Node.ln_Pri == 10)
  650.          SetTaskPri(task, -20L) ;
  651.       eraseold() ;
  652.       advancelines() ;
  653.       drawnew() ;
  654.       eraseold() ;
  655.       advancelines() ;
  656.       drawnew() ;
  657.       if (task->tc_Node.ln_Pri == 10)
  658.          SetTaskPri(task, -20L) ;
  659.       eraseold() ;
  660.       advancelines() ;
  661.       drawnew() ;
  662.       eraseold() ;
  663.       advancelines() ;
  664.       drawnew() ;
  665.       if (task->tc_Node.ln_Pri == 10)
  666.          SetTaskPri(task, -20L) ;
  667.       eraseold() ;
  668.       advancelines() ;
  669.       drawnew() ;
  670.       eraseold() ;
  671.       advancelines() ;
  672.       drawnew() ;
  673.       colors() ;
  674.    }
  675. done:
  676.    Signal(global.buddy, 1L << global.replysignum) ;
  677.    Wait(0L) ;
  678. }
  679.